from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from goods.models import SKU
from .serializers import CartSerializer, SKUCartSerializer, CartDeletedSerializer, CartSelectedAllSerializer

import pickle
import base64


class CartBaseView(APIView):

    def __init__(self):
        super().__init__()
        self.redis_conn = get_redis_connection('cart')

    def perform_authentication(self, request):
        """重写此方法 直接 pass 可以延后认证 延后到第一次通过 request.user 或 request.auth"""
        pass

    def get_user(self):
        try:
            user = self.request.user
        except Exception as e:
            user = None
        return user

    def get_cookie_cart_dict(self, cart_str):
        cart_str_bytes = cart_str.encode()
        cart_bytes = base64.b64decode(cart_str_bytes)
        cart_dict = pickle.loads(cart_bytes)
        return cart_dict

    def get_cookie_cart_str(self, cart_dict):
        cart_bytes = pickle.dumps(cart_dict)
        cart_str_bytes = base64.b64encode(cart_bytes)
        cart_str = cart_str_bytes.decode()
        return cart_str


class CartView(CartBaseView):
    """购物车增删改"""

    def get_serializer(self):
        serializer = CartSerializer(data=self.request.data)
        # 调用is_valid()进行校验
        serializer.is_valid(raise_exception=True)
        # 获取校验后的数据
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')
        return serializer, sku_id, count, selected

    def post(self, request):
        """新增"""
        serializer, sku_id, count, selected = self.get_serializer()
        user = self.get_user()
        response = Response(serializer.data, status=status.HTTP_201_CREATED)
        if user and user.is_authenticated():  # 判断用户是否通过认证
            """登录用户操作Redis购物车数据"""
            """
                hash: {'sku_id_1': 2, 'sku_id_2': 2, 'sku_id_3': 2, }
                set: {sku_id_1, sku_id_2}
            """
            pl = self.redis_conn.pipeline()
            # redis_conn.hincrby('cart_%s' % user.id, sku_id, count)  # 有值就增加 没有就新建
            pl.hincrby('cart_%s' % user.id, sku_id, count)
            if selected:
                pl.sadd('selected_%s' % user.id, sku_id)
            pl.execute()
            cart_dict = self.redis_conn.hgetall('cart_%s' % user.id)
            print(cart_dict)
        else:
            """未登录用户操作cookie购物车数据0"""
            """
            cart_dict = {
                'sku_id_1': {'count': 1, 'selected': true},
                'sku_id_2': {'count': 3, 'selected': true},
                'sku_id_4': {'count': 2, 'selected': false},
            }
            cart_bytes = pickle.dumps(cart_dict)
            cart_base64 = base64.b64encode(cart_bytes)
            cart_str = cart_base64.decode()
            response.set_cookie('cart', cart_str)
            cart_bytes = cart_str.encode()
            cart_b64 = base64.b64decode(cart_bytes)
            cart_b64
            b'\x80\x04\x95V\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x08sku_id_1\x94}\x94(\x8c\x05count\x94K\x01\x8c\x08selected\x94\x88u\x8c\x08sku_id_2\x94}\x94(h\x03K\x03h\x04\x88u\x8c\x08sku_id_4\x94}\x94(h\x03K\x02h\x04\x89uu.'
            pickle.loads(cart_b64)
            {'sku_id_1': {'count': 1, 'selected': True}, 'sku_id_2': {'count': 3, 'selected': True}, 'sku_id_4': {'count': 2, 'selected': False}}
            """
            cart_dict = {}
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                """已经添加过商品"""
                cart_dict = self.get_cookie_cart_dict(cart_str)
            # 增量计算
            if sku_id in cart_dict:
                orion_count = cart_dict[sku_id]['count']
                count += orion_count

            # 把新的商品添加到cart_dict字典中
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            cart_str = self.get_cookie_cart_str(cart_dict)
            response.set_cookie('cart', cart_str)
            print(cart_dict)

        return response

    def get(self, request):
        user = self.get_user()
        if user and user.is_authenticated():
            """登录用户获取Redis购物车数据 转成跟从cookie取出的数据格式一样"""
            cart_redis_dict = self.redis_conn.hgetall('cart_%s' % user.id)
            selected = self.redis_conn.smembers('selected_%s' % user.id)
            cart_dict = {}
            for sku_id_bytes, count_bytes in cart_redis_dict.items():
                cart_dict[int(sku_id_bytes)] = {
                    'count': int(count_bytes),
                    'selected': sku_id_bytes in selected
                }
            print(cart_redis_dict)
            print(cart_dict)
        else:
            """未登录用户获取cookie购物车数据"""
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                cart_dict = self.get_cookie_cart_dict(cart_str)
            else:
                return Response({'message': '没有购物车数据'}, status=status.HTTP_200_OK)

        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)

        for sku in skus:
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']
        serializer = SKUCartSerializer(instance=skus, many=True)
        print(serializer.data)
        return Response(serializer.data)

    def put(self, request):
        """修改购物车"""
        serializer, sku_id, count, selected = self.get_serializer()
        user = self.get_user()
        response = Response(serializer.data, status=status.HTTP_200_OK)
        if user and user.is_authenticated():
            """登录用户修改Redis购物车数据"""
            pl = self.redis_conn.pipeline()
            pl.hset('cart_%s' % user.id, sku_id, count)

            if selected:
                pl.sadd('selected_%s' % user.id, sku_id)
            else:
                pl.srem('selected_%s' % user.id, sku_id)
            pl.execute()
        else:
            """未登录用户修改cookie购物车数据"""
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                cart_dict = self.get_cookie_cart_dict(cart_str)
            else:
                return Response({'message': '没有获取到cookie'}, status=status.HTTP_400_BAD_REQUEST)
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            cart_str = self.get_cookie_cart_str(cart_dict)

            response.set_cookie('cart', cart_str)
        return response

    def delete(self, request):
        user = self.get_user()
        serializer = CartDeletedSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data.get('sku_id')
        response = Response(status=status.HTTP_204_NO_CONTENT)
        if user and user.is_authenticated():  # 判断用户是否通过认证
            """登录用户操作Redis购物车数据"""
            pl = self.redis_conn.pipeline()
            pl.hdel('cart_%s' % user.id, sku_id)
            pl.srem('selected_%s' % user.id, sku_id)
            pl.execute()
        else:
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                cart_dict = self.get_cookie_cart_dict(cart_str)
            else:
                return Response({'message': 'cookie没有获取到'}, status=status.HTTP_400_BAD_REQUEST)
            if sku_id in cart_dict:
                cart_dict.pop(sku_id)
            # 如果购物车全删了，就清空cookie
            if len(cart_dict.keys()):
                cart_str = self.get_cookie_cart_str(cart_dict)
                response.set_cookie('cart', cart_str)
            else:
                response.delete_cookie('cart')
        return response


class CartSelectAllView(CartBaseView):
    """购物车全选"""

    def put(self, request):
        serializer = CartSelectedAllSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data.get('selected')
        user = self.get_user()
        response = Response(serializer.data)
        if user and user.is_authenticated():
            cart_redis_dict = self.redis_conn.hgetall('cart_%s' % user.id)
            sku_ids = cart_redis_dict.keys()
            if selected:
                self.redis_conn.sadd('selected_%s' % user.id, *sku_ids)
            else:
                self.redis_conn.srem('selected_%s' % user.id, *sku_ids)
        else:
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                cart_dict = self.get_cookie_cart_dict(cart_str)
            else:
                return Response({'message': '未获取到cart'}, status=status.HTTP_400_BAD_REQUEST)
            for sku_id in cart_dict:
                cart_dict[sku_id]['selected'] = selected
            cart_str = self.get_cookie_cart_str(cart_dict)
            response.set_cookie('cart', cart_str)
        return response
